{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# vanilla transformer setup from transformer.py in train-vanilla-transformer, feel free to ignore this cell \n",
    "# it's just setup copying from transformer.py to be self-contained\n",
    "import torch \n",
    "from typing import List\n",
    "\n",
    "ACT2FN = {\n",
    "    'relu': torch.nn.functional.relu,\n",
    "    'gelu': torch.nn.functional.gelu,\n",
    "    'silu': torch.nn.functional.silu,\n",
    "    'swish': torch.nn.functional.silu,\n",
    "}\n",
    "\n",
    "class Attention(torch.nn.Module): # BSD -> BSD\n",
    "    def __init__(self, D=768, layer_idx=None, head_dim=64, causal=True, device=\"cuda\", gqa=False): \n",
    "        super().__init__()\n",
    "        self.D = D \n",
    "        self.head_dim = head_dim\n",
    "        self.gqa = gqa \n",
    "        assert D % head_dim == 0\n",
    "        self.nheads = D//head_dim\n",
    "        self.Wq = torch.nn.Linear(D, D)\n",
    "        self.Wk = torch.nn.Linear(D, D)\n",
    "        self.Wv = torch.nn.Linear(D, D)\n",
    "        self.causal = causal \n",
    "        self.Wo = torch.nn.Linear(D, D)\n",
    "        self.device = device\n",
    "        self.layer_idx = layer_idx\n",
    "\n",
    "    def forward(self, x: torch.Tensor, kv_cache): # input is [B, S, D] \n",
    "        B, S, D = x.shape\n",
    "        # let's make this multi-head now, ie. make each QKV [B, S, D] --> [B, nh, S, hd]\n",
    "\n",
    "        Q, K, V = self.Wq(x), self.Wk(x), self.Wv(x) # all [B, S, D]\n",
    "\n",
    "        Q = Q.view(B, S, self.nheads, self.head_dim).transpose(1,2) # [B, nh, S, hd]\n",
    "        K = K.view(B, S, self.nheads, self.head_dim).transpose(1,2) \n",
    "        V = V.view(B, S, self.nheads, self.head_dim).transpose(1,2)\n",
    "\n",
    "        # update kv cache \n",
    "        layer_idx = self.layer_idx \n",
    "        if kv_cache is not None and layer_idx is not None: \n",
    "            # its preallocated, just write to the memory of the cache using state of current_length \n",
    "            kv_cache.update(layer_idx, K, V)\n",
    "            K = kv_cache.keys[layer_idx][:, :, :kv_cache.current_length, :]\n",
    "            V = kv_cache.values[layer_idx][:, :, :kv_cache.current_length, :]\n",
    "\n",
    "        # [B, nh, S, hd] @ [B, nh, hd, S] -> [B, nh, S, S]\n",
    "        scale = torch.sqrt(torch.tensor(self.head_dim, dtype=Q.dtype, device=self.device))\n",
    "        logits = (Q @ K.transpose(-2, -1)) / scale\n",
    "        if self.causal:\n",
    "            mask = torch.triu(torch.ones_like(logits), diagonal=1).bool()\n",
    "            logits_masked = logits.masked_fill(mask, float('-inf'))\n",
    "        else:\n",
    "            logits_masked = logits\n",
    "\n",
    "        A = torch.nn.functional.softmax(logits_masked, dim=-1) # [B, nh, S, S]\n",
    "        \n",
    "        preout = torch.einsum('bnxy,bnyd->bnxd', A, V) # [B, nh, S, S] @ [B, nh, S, hd] -> [B, nh, S, hd]\n",
    "        preout = preout.transpose(1, 2).reshape(B, S, -1) # [B, nh, S, hd] -> [B, S, nh * hd]\n",
    "        \n",
    "        out = self.Wo(preout) # [B, S, D]\n",
    "        return out # [B, S, D]\n",
    "\n",
    "class MLP(torch.nn.Module): \n",
    "    def __init__(self, D, hidden_multiplier=4, act='swish', device=None): \n",
    "        super().__init__()\n",
    "        self.D = D\n",
    "        self.device = device if device is not None else torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "        self.up_proj = torch.nn.Linear(D, D*hidden_multiplier)\n",
    "        self.down_proj = torch.nn.Linear(D*hidden_multiplier, D)\n",
    "        self.act = ACT2FN[act]\n",
    "\n",
    "    def forward(self, x): # BSD -> BSD automatically on last dim \n",
    "        return self.down_proj(self.act(self.up_proj(x)))\n",
    "\n",
    "class LN(torch.nn.Module): \n",
    "    def __init__(self, D, eps=1e-9, device=None): \n",
    "        super().__init__()\n",
    "        self.D = D \n",
    "        self.eps = eps\n",
    "        self.device = device if device is not None else torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "        self.mean_scale = torch.nn.Parameter(torch.zeros(D))\n",
    "        self.std_scale = torch.nn.Parameter(torch.ones(D))\n",
    "\n",
    "    def forward(self, x): # x is [B, S, D]\n",
    "        mean = x.mean(dim=-1, keepdim=True) # [B, S, 1]\n",
    "        std = (x.var(dim=-1, keepdim=True) + self.eps)**0.5 # [B, S, 1]\n",
    "        x_norm = (x - mean)/(std) \n",
    "        return x_norm * self.std_scale + self.mean_scale\n",
    "\n",
    "class TransformerLayer(torch.nn.Module): \n",
    "    def __init__(self, D, gqa=False, device=None): \n",
    "        super().__init__()\n",
    "        self.D = D \n",
    "        self.device = device if device is not None else torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "        self.attn = Attention(D, gqa=gqa, device=self.device)\n",
    "        self.mlp = MLP(D, device=self.device)\n",
    "        self.ln1 = LN(D, device=self.device)\n",
    "        self.ln2 = LN(D, device=self.device)  \n",
    "    \n",
    "    def forward(self, x, kv_cache=None): # x is BSD\n",
    "        ln1_out = self.ln1(x)\n",
    "        attn_out = self.attn(ln1_out, kv_cache=kv_cache)\n",
    "        x = x + attn_out\n",
    "        ln2_out = self.ln2(x)\n",
    "        mlp_out = self.mlp(ln2_out)\n",
    "        x = x + mlp_out\n",
    "        return x \n",
    "\n",
    "class PositionalEmbedding(torch.nn.Module):\n",
    "    def __init__(self, max_seq_len, D, device=None):\n",
    "        super().__init__()\n",
    "        self.device = device if device is not None else torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "        self.pos_embedding = torch.nn.Parameter(torch.randn(max_seq_len, D))\n",
    "    \n",
    "    def forward(self, x): # x is [B, S, D]\n",
    "        B, S, D = x.shape\n",
    "        return x + self.pos_embedding[:S] # Broadcasting handles batch dimension\n",
    "\n",
    "class EmbeddingLayer(torch.nn.Module): \n",
    "    # this is just a lookup table \n",
    "    def __init__(self, vocab_size, D, device=None): \n",
    "        super().__init__()\n",
    "        self.device = device if device is not None else torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "        self.embedding = torch.nn.Parameter(torch.randn(vocab_size, D))\n",
    "\n",
    "    def forward(self, x): \n",
    "        return self.embedding[x]\n",
    "\n",
    "class UnembeddingLayer(torch.nn.Module): \n",
    "    # this is just a lookup table that maps embeddings back to logits\n",
    "    def __init__(self, vocab_size, D, device=None): \n",
    "        super().__init__()\n",
    "        self.device = device if device is not None else torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "        self.unembedding = torch.nn.Linear(D, vocab_size)\n",
    "\n",
    "    def forward(self, x): # x is [B, S, D]\n",
    "        # Return logits of shape [B, S, vocab_size]\n",
    "        return self.unembedding(x)\n",
    "\n",
    "class Transformer(torch.nn.Module): \n",
    "    def __init__(self, depth, hidden_dim, vocab_size, max_seq_len=16384, device=None, gqa=False): \n",
    "        super().__init__()\n",
    "        self.depth = depth\n",
    "        self.hidden_dim = hidden_dim\n",
    "        self.emb = EmbeddingLayer(vocab_size, hidden_dim, device=device)\n",
    "        self.pos_emb = PositionalEmbedding(max_seq_len, hidden_dim, device=device)\n",
    "        self.unemb = UnembeddingLayer(vocab_size, hidden_dim, device=device)\n",
    "        self.gqa = gqa \n",
    "        self.layers = torch.nn.ModuleList([TransformerLayer(hidden_dim, gqa, device=device) for _ in range(depth)])\n",
    "        for i, layer in enumerate(self.layers):\n",
    "            layer.attn.layer_idx = i  \n",
    "        self.device = device\n",
    "\n",
    "    def forward(self, x, kv_cache=None):\n",
    "        x = self.emb(x)\n",
    "        if kv_cache is not None:\n",
    "            # When decoding, only add positional embeddings for the new tokens.\n",
    "            pos_offset = kv_cache.current_length\n",
    "            pos_emb = self.pos_emb.pos_embedding[pos_offset: pos_offset + x.size(1)].unsqueeze(0)\n",
    "            x = x + pos_emb\n",
    "        else:\n",
    "            x = self.pos_emb(x)\n",
    "        for i, layer in enumerate(self.layers):\n",
    "            x = layer(x, kv_cache=kv_cache)\n",
    "        x = self.unemb(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "''' \n",
    "KV CACHE FUNDAMENTALS. WHAT EVEN IS THIS BOI? \n",
    "    - Basically its just a preallocated tensor that we fill up during autoregressive inference (\"decoding\")\n",
    "        - We use it to avoid recomputing (K, V)\n",
    "    - It naturally leads to a two-stage interpretation fo inference \n",
    "        - The first stage takes in a full prompt and populates the empty cache, this is called \"prefill\" \n",
    "        - The second stage passes in ONLY ONE TOKEN IN THE FORWARD PASS AT A TIME, \n",
    "            because the information from all past tokens IS ENTIRELY CAPTURED IN THE KV CACHE \n",
    "            - You can think of the KV cache as the \"state\" of a transformer, ie. the sufficient summary statistic \n",
    "            of all past tokens to generate the next token. Unlike RNN/SSM state, its size grows over time\n",
    "            (hence why Transformers perform better, they do zero compression of their inputs, but also take more memory)\n",
    "        - The second stage is called decoding, and we basically add [k_t, v_t] to update the cache\n",
    "        as we do a forward with each token one at a time, and then use the updated cache as our K, V matrices\n",
    "        for attention. \n",
    "    - Common question, why don't we cache queries, Q? \n",
    "        - Answer: this is a good question and important to make sure you understand. The reason is because KV cache is a \n",
    "        SUFFICIENT SUMMARY STATISTIC OF THE PAST TOKENS, and we DO NOT need to know the queries of past tokens to compute \n",
    "        the attention pattern of a SINGLE NEW TOKEN during decoding, only the query of the new token. \n",
    "        However, we DO need the keys and values of previous tokens, as the addition to the attention matrix for this \n",
    "        new token will be something like (q_t @ all_past_keys.T) @ all_past_values. \n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# kv cache implementation and profiling\n",
    "class KVCache:\n",
    "    \"\"\"\n",
    "    minimal kv cache for transformer models that preallocates memory for k/v pairs.\n",
    "    k/v tensors have shape: [batch_size, num_heads, max_seq_len, head_dim]\n",
    "    \"\"\"\n",
    "    def __init__(self, num_layers: int, batch_size: int, num_heads: int, head_dim: int, max_seq_len: int, device='cuda'):\n",
    "        self.num_layers = num_layers\n",
    "        self.batch_size = batch_size\n",
    "        self.num_heads = num_heads\n",
    "        self.head_dim = head_dim\n",
    "        self.max_seq_len = max_seq_len\n",
    "        self.device = device\n",
    "        self.current_length = 0\n",
    "        # preallocate cache memory for each layer\n",
    "        self.keys = [\n",
    "            torch.empty(batch_size, num_heads, max_seq_len, head_dim, device=device)\n",
    "            for _ in range(num_layers)\n",
    "        ]\n",
    "        self.values = [\n",
    "            torch.empty(batch_size, num_heads, max_seq_len, head_dim, device=device)\n",
    "            for _ in range(num_layers)\n",
    "        ]\n",
    "\n",
    "    def update(self, layer: int, new_keys: torch.Tensor, new_values: torch.Tensor):\n",
    "        \"\"\"\n",
    "        updates cache for a layer with new k/v tensors of shape:\n",
    "        [batch_size, num_heads, token_count, head_dim]\n",
    "        \"\"\"\n",
    "        seq_offset = self.current_length\n",
    "        token_count = new_keys.size(2)\n",
    "        self.keys[layer][:, :, seq_offset:seq_offset + token_count, :] = new_keys\n",
    "        self.values[layer][:, :, seq_offset:seq_offset + token_count, :] = new_values\n",
    "\n",
    "\n",
    "class TransformerGenerator:\n",
    "    \"\"\"\n",
    "    fast autoregressive inference using preallocated kv cache. model must accept\n",
    "    'kv_cache' arg in forward() to load/append k/v pairs from cache\n",
    "    \"\"\"\n",
    "    def __init__(self, model: Transformer, max_seq_len: int=4096):\n",
    "        self.model = model\n",
    "        self.device = next(model.parameters()).device\n",
    "        self.max_seq_len = max_seq_len\n",
    "        self.kv_cache = None\n",
    "\n",
    "    def _initialize_cache(self, batch_size: int):\n",
    "        # extract attn params from first layer to set up cache dims\n",
    "        first_layer = self.model.layers[0]\n",
    "        attn = first_layer.attn\n",
    "        \n",
    "        num_heads = attn.num_kv_heads if (hasattr(attn, 'gqa') and attn.gqa) else attn.nheads\n",
    "        head_dim = attn.head_dim\n",
    "        \n",
    "        self.kv_cache = self.model.kv_cache = KVCache(\n",
    "            self.model.depth, \n",
    "            batch_size, \n",
    "            num_heads,\n",
    "            head_dim,\n",
    "            self.max_seq_len, \n",
    "            self.device\n",
    "        )\n",
    "\n",
    "    def _prefill(self, prompt: List[int]):\n",
    "        # process initial prompt (shape [1, seq_len]) to fill kv cache\n",
    "        prompt_tensor = torch.tensor(prompt, device=self.device).unsqueeze(0)\n",
    "        batch_size = prompt_tensor.size(0)\n",
    "        self._initialize_cache(batch_size)\n",
    "        _ = self.model(prompt_tensor, kv_cache=self.kv_cache)\n",
    "        self.kv_cache.current_length = prompt_tensor.size(1)\n",
    "        return self.kv_cache\n",
    "\n",
    "    def generate(self, prompt: List[int], max_new_tokens: int):\n",
    "        \"\"\"\n",
    "        generates tokens autoregressively given a prompt\n",
    "        returns: list[int] with prompt + new tokens\n",
    "        \"\"\"\n",
    "        kv_cache = self._prefill(prompt)\n",
    "        generated = list(prompt)\n",
    "        for _ in range(max_new_tokens):\n",
    "            # feed last token through model, shape [1,1]\n",
    "            input_tensor = torch.tensor([[generated[-1]]], device=self.device)\n",
    "            logits = self.model(input_tensor, kv_cache=kv_cache)\n",
    "            next_token = int(torch.argmax(logits[:, -1, :], dim=-1).item())\n",
    "            generated.append(next_token)\n",
    "            kv_cache.current_length += 1\n",
    "        return generated\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [08:41<00:00, 130.46s/it]\n"
     ]
    },
    {
     "data": {
      "image/png": "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Th2cOHGiUM6PiApAEBEVsu+++04AEAkJCTn2ARAjR45U3w4KChIARNWqVUVaWpp6+6+//ioAiCtXrqi3+fr6CgBi3rx56m1paWnCx8dH2NraivT0dCGEECtWrBAARFhYmMZjZz1WUFCQelvHjh2Fs7Oz1ufm7OwsOnbs+Nr94eHhQiqVihkzZmhsv3LlitDX19fYnnU+f/31l8b52Nvbi549e6q3zZs3TwAQ27dvV29LSUkRVapU0fp88nOds9pOnjz5jddCCCEWLFggRo0aJdasWSM2b94sPv/8c6Gvry88PT1FXFzca+9namoqBg8enOfxs0yfPl0AEAcPHtT6Pq968uSJ0NfXF8uXL1dva9Kkiejatav69q1btwQAsWjRIo37fvbZZ8LMzEwkJycLIYQ4duyYACDWrFmj0W7v3r05tjs7OwsAYu/evTliyjpedn5+fsLNzU19+/Hjx0JfX19069ZNo92UKVMEAI3rOH36dGFqaipu376t0XbixIlCKpWKe/fuCSGE2L59uwAg5syZo26TmZkpmjVrJgCIFStW5Igruy+++EIAEMeOHVNvS0hIEK6ursLFxUUoFAohhBDLli3L8foSQghvb2/RqlWrfMcdFhYmAAgLCwsRFRX1xhhzk9/3+5seLz+fM9q+17t27SqqVaumVWwff/yxMDY21vpciKhwcTgfERW6mJgY6Ovr56tXZ+jQoRpzDJo1awZANWQoO319fYwYMUJ9WyaTYcSIEYiKisL58+ffMvK3t3XrViiVSvTu3RvR0dHqP3t7e3h6euboPTIzM8PAgQPVt2UyGRo0aKBx3nv37kXFihXRpUsX9TYjIyMMHz483/Fpc51btGgBIYRWvVCff/45Fi1ahP79+6Nnz55YsGAB/vzzT4SEhGDx4sX5ji83R48exdSpU9G7d++3mv+xfv166OnpoWfPnupt/fr1w549e9RD8Ly8vODj44MNGzao2ygUCmzevBmdO3dWz2PatGkT5HI52rZtq/E8161bF2ZmZjmeZ1dXV/j5+eWIKfu8qLi4OERHR8PX1xd3795FXFwcAFW1wszMTHz22Wca9x09enSO423atAnNmjVDuXLlNOJq06YNFAoFjh49CkBVoVBfXx+ffvqp+r5SqTTXY+Zm9+7daNCgAd577z31NjMzM3z88ccIDw9XD6/r0aMH9PX1Na7n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nHfDDTeooqJCR44c0dq1a3Xttdfqu9/9rpYsWaKOjo6L/vqDRUVFhfufZ599VlFRUV7P/uVf/sXqEgFgSCBEAYAPuu6665SUlKSf/exn55zz4x//+Iytbc8++6xGjRrl/vjee+/V0qVL9cQTTygxMVExMTF6/PHH1dHRoUcffVSxsbFKS0vTiy++eMbn379/v6644gqFhIRoypQp2rhxo9f4nj17dOONNyoiIkKJiYn6u7/7O504ccI9fs011+iBBx7QQw89pPj4eC1atOis30dnZ6cef/xxpaWlKTg4WNOnT9e6devc4zabTTt27NDjjz9+3tWU4OBgJSUlKTU1VTNnztS//du/6a233tLatWv10ksvuefV1NToG9/4hkaOHKmoqCgtWLBAu3fv9vpcf/nLXzRnzhyFhIQoPj5et912m3vs9OnTuueeezRixAiFhYXpxhtv1Geffeb141966SXZ7XaFhYXptttu08mTJ8+o96233tLMmTMVEhKiMWPG6LHHHvMKe5999pnmzZunkJAQTZ48We+///45v3dJSkpKcv8THR0tm83m/jghIUG/+tWvzvk6f5HL5dL999+viRMnqrS09ILqtdls+v3vf6/bbrtNYWFhGjdunFavXu31ui1fvlwjR45UaGioxo0bd9ZfewDg6whRAOCD/P399cQTT+i//uu/dPTo0Uv6XB988IHKy8u1adMm/epXv9LKlSu1ZMkSjRgxQoWFhfqnf/on/eM//uMZX+fRRx/VI488ol27dmnu3Lm6+eab3UGgpqZGCxYs0IwZM7R9+3atW7dOVVVVuvPOO70+x//+7/8qKChIW7Zs0e9+97uz1vfrX/9av/zlL/X000/r448/1qJFi3TLLbe4Q0lFRYUuv/xyPfLIIxe1mrJgwQJlZGToz3/+s/vZHXfcoerqaq1du1Y7duzQzJkztXDhQp06dUqS9M477+i2227T4sWLtWvXLq1fv16ZmZnuH3/vvfdq+/btWr16tbZu3SrDMLR48WK1t7dLkgoLC/X3f//3euCBB1RcXKxrr71WP/nJT7zq2rx5s+655x5997vf1d69e/X888/rpZde0k9/+lNJZrj86le/qqCgIBUWFup3v/udvve97/Xqe+/pfK9zT62trbrjjjtUXFyszZs3y263n7febo899pjuvPNOffzxx1q8eLGWL1/u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",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Average time per decoded token (averaged over 1 runs):\n",
      "----------------------------------------------------\n",
      "Decoding Method | Tokens Decoded | Avg ms/token\n",
      "----------------------------------------------------\n",
      "No KV Cache     |            512 |         5.45\n",
      "With KV Cache   |            512 |         3.59\n",
      "----------------------------------------------------\n",
      "No KV Cache     |           2048 |         8.57\n",
      "With KV Cache   |           2048 |         2.90\n",
      "----------------------------------------------------\n",
      "No KV Cache     |           4096 |        17.87\n",
      "With KV Cache   |           4096 |         2.89\n",
      "----------------------------------------------------\n",
      "No KV Cache     |           8192 |        47.13\n",
      "With KV Cache   |           8192 |         2.76\n",
      "----------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "import time\n",
    "import torch\n",
    "import matplotlib.pyplot as plt\n",
    "from tqdm import tqdm\n",
    "import numpy as np\n",
    "\n",
    "# this profiling takes ~10min on a single H100, you can reduce any of the below to make it faster \n",
    "# (hidden_dim, num_layers, input_seq_len, num_decode_tokens, n_runs)\n",
    "vocab_size = 256\n",
    "hidden_dim = 512\n",
    "n_layers = 6\n",
    "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
    "\n",
    "model = Transformer(depth=n_layers, hidden_dim=hidden_dim, vocab_size=vocab_size, device=device)\n",
    "model = model.to(device)\n",
    "model.eval()\n",
    "\n",
    "generator = TransformerGenerator(model)\n",
    "\n",
    "input_seq_len = 512\n",
    "num_decode_tokens = [512, 2048, 4096, 8192]\n",
    "decode_times_no_kv = []\n",
    "decode_times_kv = []\n",
    "n_runs = 1\n",
    "\n",
    "with torch.no_grad():\n",
    "    for n_tokens in tqdm(num_decode_tokens):\n",
    "        batch_size = 1\n",
    "        times_for_this_n_no_kv = []\n",
    "        times_for_this_n_kv = []\n",
    "\n",
    "        for _ in range(n_runs):\n",
    "            prompt_tensor = torch.randint(0, vocab_size, (batch_size, input_seq_len)).to(device)\n",
    "            prompt_list = prompt_tensor.squeeze(0).tolist()\n",
    "\n",
    "            x = prompt_tensor.clone()\n",
    "            start_time_no_kv = time.time()\n",
    "            for _ in range(n_tokens):\n",
    "                logits = model(x)\n",
    "                # get next token prediction [B, 1]\n",
    "                next_token = torch.argmax(logits[:, -1:, :], dim=-1)\n",
    "                x = torch.cat([x, next_token], dim=1)\n",
    "            torch.cuda.synchronize()\n",
    "            end_time_no_kv = time.time()\n",
    "            times_for_this_n_no_kv.append((end_time_no_kv - start_time_no_kv) * 1000)\n",
    "\n",
    "            start_time_kv = time.time()\n",
    "            _ = generator.generate(prompt_list, n_tokens)\n",
    "            torch.cuda.synchronize()\n",
    "            end_time_kv = time.time()\n",
    "            times_for_this_n_kv.append((end_time_kv - start_time_kv) * 1000)\n",
    "\n",
    "        avg_time_no_kv = np.mean(times_for_this_n_no_kv)\n",
    "        decode_times_no_kv.append(avg_time_no_kv)\n",
    "        avg_time_kv = np.mean(times_for_this_n_kv)\n",
    "        decode_times_kv.append(avg_time_kv)\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(num_decode_tokens, decode_times_no_kv, marker='o', label='No KV Cache')\n",
    "plt.plot(num_decode_tokens, decode_times_kv, marker='s', label='With KV Cache')\n",
    "plt.xlabel('Number of Decoded Tokens')\n",
    "plt.ylabel('Total Time (ms)')\n",
    "plt.title(f'Decoding Latency vs Number of Generated Tokens\\n(Input Length: {input_seq_len}, Averaged over {n_runs} runs)')\n",
    "plt.grid(True)\n",
    "plt.legend()\n",
    "plt.yscale('log')\n",
    "plt.xscale('log')\n",
    "plt.show()\n",
    "\n",
    "print(f\"\\nAverage time per decoded token (averaged over {n_runs} runs):\")\n",
    "print(\"----------------------------------------------------\")\n",
    "print(\"Decoding Method | Tokens Decoded | Avg ms/token\")\n",
    "print(\"----------------------------------------------------\")\n",
    "for n_tokens, total_time_no_kv, total_time_kv in zip(num_decode_tokens, decode_times_no_kv, decode_times_kv):\n",
    "    avg_per_token_no_kv = total_time_no_kv / n_tokens if n_tokens > 0 else 0\n",
    "    avg_per_token_kv = total_time_kv / n_tokens if n_tokens > 0 else 0\n",
    "    print(f\"No KV Cache     | {n_tokens:14d} | {avg_per_token_no_kv:12.2f}\")\n",
    "    print(f\"With KV Cache   | {n_tokens:14d} | {avg_per_token_kv:12.2f}\")\n",
    "    print(\"----------------------------------------------------\")\n",
    "\n",
    "# Hurray! We can see that without KV cache, decoding latency is nonlinear (it will be quadratic if you zoom out more)\n",
    "# but with KV cache, decoding latency is linear in sequence length, so this is a O(S) big win!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "envi",
   "language": "python",
   "name": "lingua_env"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
